home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / matrix.rb < prev    next >
Text File  |  2008-09-19  |  28KB  |  1,278 lines

  1. #--
  2. #   matrix.rb - 
  3. #       $Release Version: 1.0$
  4. #       $Revision: 1.11 $
  5. #       $Date: 1999/10/06 11:01:53 $
  6. #       Original Version from Smalltalk-80 version
  7. #          on July 23, 1985 at 8:37:17 am
  8. #       by Keiju ISHITSUKA
  9. #++
  10. #
  11. # = matrix.rb
  12. #
  13. # An implementation of Matrix and Vector classes.
  14. #
  15. # Author:: Keiju ISHITSUKA
  16. # Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly)) 
  17. #
  18. # See classes Matrix and Vector for documentation. 
  19. #
  20.  
  21.  
  22. require "e2mmap.rb"
  23.  
  24. module ExceptionForMatrix # :nodoc:
  25.   extend Exception2MessageMapper
  26.   def_e2message(TypeError, "wrong argument type %s (expected %s)")
  27.   def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
  28.   
  29.   def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
  30.   def_exception("ErrNotRegular", "Not Regular Matrix")
  31.   def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
  32. end
  33.  
  34. #
  35. # The +Matrix+ class represents a mathematical matrix, and provides methods for creating
  36. # special-case matrices (zero, identity, diagonal, singular, vector), operating on them
  37. # arithmetically and algebraically, and determining their mathematical properties (trace, rank,
  38. # inverse, determinant).
  39. #
  40. # Note that although matrices should theoretically be rectangular, this is not
  41. # enforced by the class.
  42. #
  43. # Also note that the determinant of integer matrices may be incorrectly calculated unless you
  44. # also <tt>require 'mathn'</tt>.  This may be fixed in the future.
  45. #
  46. # == Method Catalogue
  47. #
  48. # To create a matrix:
  49. # * <tt> Matrix[*rows]                  </tt>
  50. # * <tt> Matrix.[](*rows)               </tt>
  51. # * <tt> Matrix.rows(rows, copy = true) </tt>
  52. # * <tt> Matrix.columns(columns)        </tt>
  53. # * <tt> Matrix.diagonal(*values)       </tt>
  54. # * <tt> Matrix.scalar(n, value)        </tt>
  55. # * <tt> Matrix.scalar(n, value)        </tt>
  56. # * <tt> Matrix.identity(n)             </tt>
  57. # * <tt> Matrix.unit(n)                 </tt>
  58. # * <tt> Matrix.I(n)                    </tt>
  59. # * <tt> Matrix.zero(n)                 </tt>
  60. # * <tt> Matrix.row_vector(row)         </tt>
  61. # * <tt> Matrix.column_vector(column)   </tt>
  62. #
  63. # To access Matrix elements/columns/rows/submatrices/properties: 
  64. # * <tt>  [](i, j)                      </tt>
  65. # * <tt> #row_size                      </tt>
  66. # * <tt> #column_size                   </tt>
  67. # * <tt> #row(i)                        </tt>
  68. # * <tt> #column(j)                     </tt>
  69. # * <tt> #collect                       </tt>
  70. # * <tt> #map                           </tt>
  71. # * <tt> #minor(*param)                 </tt>
  72. #
  73. # Properties of a matrix:
  74. # * <tt> #regular?                      </tt>
  75. # * <tt> #singular?                     </tt>
  76. # * <tt> #square?                       </tt>
  77. #
  78. # Matrix arithmetic:
  79. # * <tt>  *(m)                          </tt>
  80. # * <tt>  +(m)                          </tt>
  81. # * <tt>  -(m)                          </tt>
  82. # * <tt> #/(m)                          </tt>
  83. # * <tt> #inverse                       </tt>
  84. # * <tt> #inv                           </tt>
  85. # * <tt>  **                            </tt>
  86. #
  87. # Matrix functions:
  88. # * <tt> #determinant                   </tt>
  89. # * <tt> #det                           </tt>
  90. # * <tt> #rank                          </tt>
  91. # * <tt> #trace                         </tt>
  92. # * <tt> #tr                            </tt>
  93. # * <tt> #transpose                     </tt>
  94. # * <tt> #t                             </tt>
  95. #
  96. # Conversion to other data types:
  97. # * <tt> #coerce(other)                 </tt>
  98. # * <tt> #row_vectors                   </tt>
  99. # * <tt> #column_vectors                </tt>
  100. # * <tt> #to_a                          </tt>
  101. #
  102. # String representations:
  103. # * <tt> #to_s                          </tt>
  104. # * <tt> #inspect                       </tt>
  105. #
  106. class Matrix
  107.   @RCS_ID='-$Id: matrix.rb,v 1.11 1999/10/06 11:01:53 keiju Exp keiju $-'
  108.   
  109. #  extend Exception2MessageMapper
  110.   include ExceptionForMatrix
  111.   
  112.   # instance creations
  113.   private_class_method :new
  114.   
  115.   #
  116.   # Creates a matrix where each argument is a row.
  117.   #   Matrix[ [25, 93], [-1, 66] ]
  118.   #      =>  25 93
  119.   #          -1 66
  120.   #
  121.   def Matrix.[](*rows)
  122.     new(:init_rows, rows, false)
  123.   end
  124.   
  125.   #
  126.   # Creates a matrix where +rows+ is an array of arrays, each of which is a row
  127.   # to the matrix.  If the optional argument +copy+ is false, use the given
  128.   # arrays as the internal structure of the matrix without copying.
  129.   #   Matrix.rows([[25, 93], [-1, 66]])
  130.   #      =>  25 93
  131.   #          -1 66
  132.   def Matrix.rows(rows, copy = true)
  133.     new(:init_rows, rows, copy)
  134.   end
  135.   
  136.   #
  137.   # Creates a matrix using +columns+ as an array of column vectors.
  138.   #   Matrix.columns([[25, 93], [-1, 66]])
  139.   #      =>  25 -1
  140.   #          93 66
  141.   #
  142.   #
  143.   def Matrix.columns(columns)
  144.     rows = (0 .. columns[0].size - 1).collect {
  145.       |i|
  146.       (0 .. columns.size - 1).collect {
  147.         |j|
  148.         columns[j][i]
  149.       }
  150.     }
  151.     Matrix.rows(rows, false)
  152.   end
  153.   
  154.   #
  155.   # Creates a matrix where the diagonal elements are composed of +values+.
  156.   #   Matrix.diagonal(9, 5, -3)
  157.   #     =>  9  0  0
  158.   #         0  5  0
  159.   #         0  0 -3
  160.   #
  161.   def Matrix.diagonal(*values)
  162.     size = values.size
  163.     rows = (0 .. size  - 1).collect {
  164.       |j|
  165.       row = Array.new(size).fill(0, 0, size)
  166.       row[j] = values[j]
  167.       row
  168.     }
  169.     rows(rows, false)
  170.   end
  171.   
  172.   #
  173.   # Creates an +n+ by +n+ diagonal matrix where each diagonal element is
  174.   # +value+.
  175.   #   Matrix.scalar(2, 5)
  176.   #     => 5 0
  177.   #        0 5
  178.   #
  179.   def Matrix.scalar(n, value)
  180.     Matrix.diagonal(*Array.new(n).fill(value, 0, n))
  181.   end
  182.  
  183.   #
  184.   # Creates an +n+ by +n+ identity matrix.
  185.   #   Matrix.identity(2)
  186.   #     => 1 0
  187.   #        0 1
  188.   #
  189.   def Matrix.identity(n)
  190.     Matrix.scalar(n, 1)
  191.   end
  192.   class << Matrix 
  193.     alias unit identity
  194.     alias I identity
  195.   end
  196.   
  197.   #
  198.   # Creates an +n+ by +n+ zero matrix.
  199.   #   Matrix.zero(2)
  200.   #     => 0 0
  201.   #        0 0
  202.   #
  203.   def Matrix.zero(n)
  204.     Matrix.scalar(n, 0)
  205.   end
  206.   
  207.   #
  208.   # Creates a single-row matrix where the values of that row are as given in
  209.   # +row+.
  210.   #   Matrix.row_vector([4,5,6])
  211.   #     => 4 5 6
  212.   #
  213.   def Matrix.row_vector(row)
  214.     case row
  215.     when Vector
  216.       Matrix.rows([row.to_a], false)
  217.     when Array
  218.       Matrix.rows([row.dup], false)
  219.     else
  220.       Matrix.rows([[row]], false)
  221.     end
  222.   end
  223.   
  224.   #
  225.   # Creates a single-column matrix where the values of that column are as given
  226.   # in +column+.
  227.   #   Matrix.column_vector([4,5,6])
  228.   #     => 4
  229.   #        5
  230.   #        6
  231.   #
  232.   def Matrix.column_vector(column)
  233.     case column
  234.     when Vector
  235.       Matrix.columns([column.to_a])
  236.     when Array
  237.       Matrix.columns([column])
  238.     else
  239.       Matrix.columns([[column]])
  240.     end
  241.   end
  242.  
  243.   #
  244.   # This method is used by the other methods that create matrices, and is of no
  245.   # use to general users.
  246.   #
  247.   def initialize(init_method, *argv)
  248.     self.send(init_method, *argv)
  249.   end
  250.   
  251.   def init_rows(rows, copy)
  252.     if copy
  253.       @rows = rows.collect{|row| row.dup}
  254.     else
  255.       @rows = rows
  256.     end
  257.     self
  258.   end
  259.   private :init_rows
  260.   
  261.   #
  262.   # Returns element (+i+,+j+) of the matrix.  That is: row +i+, column +j+.
  263.   #
  264.   def [](i, j)
  265.     @rows[i][j]
  266.   end
  267.  
  268.   #
  269.   # Returns the number of rows.
  270.   #
  271.   def row_size
  272.     @rows.size
  273.   end
  274.   
  275.   #
  276.   # Returns the number of columns.  Note that it is possible to construct a
  277.   # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
  278.   # mathematically unsound.  This method uses the first row to determine the
  279.   # result.
  280.   #
  281.   def column_size
  282.     @rows[0].size
  283.   end
  284.  
  285.   #
  286.   # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
  287.   # an array).  When a block is given, the elements of that vector are iterated.
  288.   #
  289.   def row(i) # :yield: e
  290.     if block_given?
  291.       for e in @rows[i]
  292.         yield e
  293.       end
  294.     else
  295.       Vector.elements(@rows[i])
  296.     end
  297.   end
  298.  
  299.   #
  300.   # Returns column vector number +j+ of the matrix as a Vector (starting at 0
  301.   # like an array).  When a block is given, the elements of that vector are
  302.   # iterated.
  303.   #
  304.   def column(j) # :yield: e
  305.     if block_given?
  306.       0.upto(row_size - 1) do
  307.         |i|
  308.         yield @rows[i][j]
  309.       end
  310.     else
  311.       col = (0 .. row_size - 1).collect {
  312.         |i|
  313.         @rows[i][j]
  314.       }
  315.       Vector.elements(col, false)
  316.     end
  317.   end
  318.   
  319.   #
  320.   # Returns a matrix that is the result of iteration of the given block over all
  321.   # elements of the matrix.
  322.   #   Matrix[ [1,2], [3,4] ].collect { |i| i**2 }
  323.   #     => 1  4
  324.   #        9 16
  325.   #
  326.   def collect # :yield: e
  327.     rows = @rows.collect{|row| row.collect{|e| yield e}}
  328.     Matrix.rows(rows, false)
  329.   end
  330.   alias map collect
  331.   
  332.   #
  333.   # Returns a section of the matrix.  The parameters are either:
  334.   # *  start_row, nrows, start_col, ncols; OR
  335.   # *  col_range, row_range
  336.   #
  337.   #   Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
  338.   #     => 9 0 0
  339.   #        0 5 0
  340.   #
  341.   def minor(*param)
  342.     case param.size
  343.     when 2
  344.       from_row = param[0].first
  345.       size_row = param[0].end - from_row
  346.       size_row += 1 unless param[0].exclude_end?
  347.       from_col = param[1].first
  348.       size_col = param[1].end - from_col
  349.       size_col += 1 unless param[1].exclude_end?
  350.     when 4
  351.       from_row = param[0]
  352.       size_row = param[1]
  353.       from_col = param[2]
  354.       size_col = param[3]
  355.     else
  356.       Matrix.Raise ArgumentError, param.inspect
  357.     end
  358.     
  359.     rows = @rows[from_row, size_row].collect{
  360.       |row|
  361.       row[from_col, size_col]
  362.     }
  363.     Matrix.rows(rows, false)
  364.   end
  365.  
  366.   #--
  367.   # TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  368.   #++
  369.  
  370.   #
  371.   # Returns +true+ if this is a regular matrix.
  372.   #
  373.   def regular?
  374.     square? and rank == column_size
  375.   end
  376.   
  377.   #
  378.   # Returns +true+ is this is a singular (i.e. non-regular) matrix.
  379.   #
  380.   def singular?
  381.     not regular?
  382.   end
  383.  
  384.   #
  385.   # Returns +true+ is this is a square matrix.  See note in column_size about this
  386.   # being unreliable, though.
  387.   #
  388.   def square?
  389.     column_size == row_size
  390.   end
  391.   
  392.   #--
  393.   # OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  394.   #++
  395.  
  396.   #
  397.   # Returns +true+ if and only if the two matrices contain equal elements.
  398.   #
  399.   def ==(other)
  400.     return false unless Matrix === other
  401.     
  402.     other.compare_by_row_vectors(@rows)
  403.   end
  404.   alias eql? ==
  405.   
  406.   #
  407.   # Not really intended for general consumption.
  408.   #
  409.   def compare_by_row_vectors(rows)
  410.     return false unless @rows.size == rows.size
  411.     
  412.     0.upto(@rows.size - 1) do
  413.       |i|
  414.       return false unless @rows[i] == rows[i]
  415.     end
  416.     true
  417.   end
  418.   
  419.   #
  420.   # Returns a clone of the matrix, so that the contents of each do not reference
  421.   # identical objects.
  422.   #
  423.   def clone
  424.     Matrix.rows(@rows)
  425.   end
  426.   
  427.   #
  428.   # Returns a hash-code for the matrix.
  429.   #
  430.   def hash
  431.     value = 0
  432.     for row in @rows
  433.       for e in row
  434.         value ^= e.hash
  435.       end
  436.     end
  437.     return value
  438.   end
  439.   
  440.   #--
  441.   # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  442.   #++
  443.   
  444.   #
  445.   # Matrix multiplication.
  446.   #   Matrix[[2,4], [6,8]] * Matrix.identity(2)
  447.   #     => 2 4
  448.   #        6 8
  449.   #
  450.   def *(m) # m is matrix or vector or number
  451.     case(m)
  452.     when Numeric
  453.       rows = @rows.collect {
  454.         |row|
  455.         row.collect {
  456.           |e|
  457.           e * m
  458.         }
  459.       }
  460.       return Matrix.rows(rows, false)
  461.     when Vector
  462.       m = Matrix.column_vector(m)
  463.       r = self * m
  464.       return r.column(0)
  465.     when Matrix
  466.       Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
  467.     
  468.       rows = (0 .. row_size - 1).collect {
  469.         |i|
  470.         (0 .. m.column_size - 1).collect {
  471.           |j|
  472.           vij = 0
  473.           0.upto(column_size - 1) do
  474.             |k|
  475.             vij += self[i, k] * m[k, j]
  476.           end
  477.           vij
  478.         }
  479.       }
  480.       return Matrix.rows(rows, false)
  481.     else
  482.       x, y = m.coerce(self)
  483.       return x * y
  484.     end
  485.   end
  486.   
  487.   #
  488.   # Matrix addition.
  489.   #   Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
  490.   #     =>  6  0
  491.   #        -4 12
  492.   #
  493.   def +(m)
  494.     case m
  495.     when Numeric
  496.       Matrix.Raise ErrOperationNotDefined, "+"
  497.     when Vector
  498.       m = Matrix.column_vector(m)
  499.     when Matrix
  500.     else
  501.       x, y = m.coerce(self)
  502.       return x + y
  503.     end
  504.     
  505.     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
  506.     
  507.     rows = (0 .. row_size - 1).collect {
  508.       |i|
  509.       (0 .. column_size - 1).collect {
  510.         |j|
  511.         self[i, j] + m[i, j]
  512.       }
  513.     }
  514.     Matrix.rows(rows, false)
  515.   end
  516.  
  517.   #
  518.   # Matrix subtraction.
  519.   #   Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
  520.   #     => -8  2
  521.   #         8  1
  522.   #
  523.   def -(m)
  524.     case m
  525.     when Numeric
  526.       Matrix.Raise ErrOperationNotDefined, "-"
  527.     when Vector
  528.       m = Matrix.column_vector(m)
  529.     when Matrix
  530.     else
  531.       x, y = m.coerce(self)
  532.       return x - y
  533.     end
  534.     
  535.     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
  536.     
  537.     rows = (0 .. row_size - 1).collect {
  538.       |i|
  539.       (0 .. column_size - 1).collect {
  540.         |j|
  541.         self[i, j] - m[i, j]
  542.       }
  543.     }
  544.     Matrix.rows(rows, false)
  545.   end
  546.   
  547.   #
  548.   # Matrix division (multiplication by the inverse).
  549.   #   Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
  550.   #     => -7  1
  551.   #        -3 -6
  552.   #
  553.   def /(other)
  554.     case other
  555.     when Numeric
  556.       rows = @rows.collect {
  557.         |row|
  558.         row.collect {
  559.           |e|
  560.           e / other
  561.         }
  562.       }
  563.       return Matrix.rows(rows, false)
  564.     when Matrix
  565.       return self * other.inverse
  566.     else
  567.       x, y = other.coerce(self)
  568.       rerurn x / y
  569.     end
  570.   end
  571.  
  572.   #
  573.   # Returns the inverse of the matrix.
  574.   #   Matrix[[1, 2], [2, 1]].inverse
  575.   #     => -1  1
  576.   #         0 -1
  577.   #
  578.   def inverse
  579.     Matrix.Raise ErrDimensionMismatch unless square?
  580.     Matrix.I(row_size).inverse_from(self)
  581.   end
  582.   alias inv inverse
  583.  
  584.   #
  585.   # Not for public consumption?
  586.   #
  587.   def inverse_from(src)
  588.     size = row_size - 1
  589.     a = src.to_a
  590.     
  591.     for k in 0..size
  592.       i = k
  593.       akk = a[k][k].abs
  594.       for j in (k+1)..size
  595.         v = a[j][k].abs
  596.         if v > akk
  597.           i = j
  598.           akk = v
  599.         end
  600.       end
  601.       Matrix.Raise ErrNotRegular if akk == 0
  602.       if i != k
  603.         a[i], a[k] = a[k], a[i]
  604.         @rows[i], @rows[k] = @rows[k], @rows[i]
  605.       end
  606.       akk = a[k][k]
  607.       
  608.       for i in 0 .. size
  609.         next if i == k
  610.         q = a[i][k] / akk
  611.         a[i][k] = 0
  612.         
  613.         (k + 1).upto(size) do   
  614.           |j|
  615.           a[i][j] -= a[k][j] * q
  616.         end
  617.         0.upto(size) do
  618.           |j|
  619.           @rows[i][j] -= @rows[k][j] * q
  620.         end
  621.       end
  622.       
  623.       (k + 1).upto(size) do
  624.         |j|
  625.         a[k][j] /= akk
  626.       end
  627.       0.upto(size) do
  628.         |j|
  629.         @rows[k][j] /= akk
  630.       end
  631.     end
  632.     self
  633.   end
  634.   #alias reciprocal inverse
  635.   
  636.   #
  637.   # Matrix exponentiation.  Defined for integer powers only.  Equivalent to
  638.   # multiplying the matrix by itself N times.
  639.   #   Matrix[[7,6], [3,9]] ** 2
  640.   #     => 67 96
  641.   #        48 99
  642.   #
  643.   def ** (other)
  644.     if other.kind_of?(Integer)
  645.       x = self
  646.       if other <= 0
  647.         x = self.inverse
  648.         return Matrix.identity(self.column_size) if other == 0
  649.         other = -other
  650.       end
  651.       z = x
  652.       n = other  - 1
  653.       while n != 0
  654.         while (div, mod = n.divmod(2)
  655.                mod == 0)
  656.           x = x * x
  657.           n = div
  658.         end
  659.         z *= x
  660.         n -= 1
  661.       end
  662.       z
  663.     elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
  664.       Matrix.Raise ErrOperationNotDefined, "**"
  665.     else
  666.       Matrix.Raise ErrOperationNotDefined, "**"
  667.     end
  668.   end
  669.   
  670.   #--
  671.   # MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  672.   #++
  673.   
  674.   #
  675.   # Returns the determinant of the matrix.  If the matrix is not square, the
  676.   # result is 0.
  677.   #   Matrix[[7,6], [3,9]].determinant
  678.   #     => 63
  679.   #
  680.   def determinant
  681.     return 0 unless square?
  682.     
  683.     size = row_size - 1
  684.     a = to_a
  685.     
  686.     det = 1
  687.     k = 0
  688.     begin 
  689.       if (akk = a[k][k]) == 0
  690.         i = k
  691.         begin
  692.           return 0 if (i += 1) > size
  693.         end while a[i][k] == 0
  694.         a[i], a[k] = a[k], a[i]
  695.         akk = a[k][k]
  696.         det *= -1
  697.       end
  698.       (k + 1).upto(size) do
  699.         |i|
  700.         q = a[i][k] / akk
  701.         (k + 1).upto(size) do
  702.           |j|
  703.           a[i][j] -= a[k][j] * q
  704.         end
  705.       end
  706.       det *= akk
  707.     end while (k += 1) <= size
  708.     det
  709.   end
  710.   alias det determinant
  711.         
  712.   #
  713.   # Returns the rank of the matrix.  Beware that using Float values, with their
  714.   # usual lack of precision, can affect the value returned by this method.  Use
  715.   # Rational values instead if this is important to you.
  716.   #   Matrix[[7,6], [3,9]].rank
  717.   #     => 2
  718.   #
  719.   def rank
  720.     if column_size > row_size
  721.       a = transpose.to_a
  722.       a_column_size = row_size
  723.       a_row_size = column_size
  724.     else
  725.       a = to_a
  726.       a_column_size = column_size
  727.       a_row_size = row_size
  728.     end
  729.     rank = 0
  730.     k = 0
  731.     begin
  732.       if (akk = a[k][k]) == 0
  733.         i = k
  734.         exists = true
  735.         begin
  736.           if (i += 1) > a_column_size - 1
  737.             exists = false
  738.             break
  739.           end
  740.         end while a[i][k] == 0
  741.         if exists
  742.           a[i], a[k] = a[k], a[i]
  743.           akk = a[k][k]
  744.         else
  745.           i = k
  746.           exists = true
  747.           begin
  748.             if (i += 1) > a_row_size - 1
  749.               exists = false
  750.               break
  751.             end
  752.           end while a[k][i] == 0
  753.           if exists
  754.             k.upto(a_column_size - 1) do
  755.               |j|
  756.               a[j][k], a[j][i] = a[j][i], a[j][k]
  757.             end
  758.             akk = a[k][k]
  759.           else
  760.             next
  761.           end
  762.         end
  763.       end
  764.       (k + 1).upto(a_row_size - 1) do
  765.         |i|
  766.         q = a[i][k] / akk
  767.         (k + 1).upto(a_column_size - 1) do
  768.           |j|
  769.           a[i][j] -= a[k][j] * q
  770.         end
  771.       end
  772.       rank += 1
  773.     end while (k += 1) <= a_column_size - 1
  774.     return rank
  775.   end
  776.  
  777.   #
  778.   # Returns the trace (sum of diagonal elements) of the matrix.
  779.   #   Matrix[[7,6], [3,9]].trace
  780.   #     => 16
  781.   #
  782.   def trace
  783.     tr = 0
  784.     0.upto(column_size - 1) do
  785.       |i|
  786.       tr += @rows[i][i]
  787.     end
  788.     tr
  789.   end
  790.   alias tr trace
  791.   
  792.   #
  793.   # Returns the transpose of the matrix.
  794.   #   Matrix[[1,2], [3,4], [5,6]]
  795.   #     => 1 2
  796.   #        3 4
  797.   #        5 6
  798.   #   Matrix[[1,2], [3,4], [5,6]].transpose
  799.   #     => 1 3 5
  800.   #        2 4 6
  801.   #
  802.   def transpose
  803.     Matrix.columns(@rows)
  804.   end
  805.   alias t transpose
  806.   
  807.   #--
  808.   # CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  809.   #++
  810.   
  811.   #
  812.   # FIXME: describe #coerce.
  813.   #
  814.   def coerce(other)
  815.     case other
  816.     when Numeric
  817.       return Scalar.new(other), self
  818.     else
  819.       raise TypeError, "#{self.class} can't be coerced into #{other.class}"
  820.     end
  821.   end
  822.  
  823.   #
  824.   # Returns an array of the row vectors of the matrix.  See Vector.
  825.   #
  826.   def row_vectors
  827.     rows = (0 .. row_size - 1).collect {
  828.       |i|
  829.       row(i)
  830.     }
  831.     rows
  832.   end
  833.   
  834.   #
  835.   # Returns an array of the column vectors of the matrix.  See Vector.
  836.   #
  837.   def column_vectors
  838.     columns = (0 .. column_size - 1).collect {
  839.       |i|
  840.       column(i)
  841.     }
  842.     columns
  843.   end
  844.   
  845.   #
  846.   # Returns an array of arrays that describe the rows of the matrix.
  847.   #
  848.   def to_a
  849.     @rows.collect{|row| row.collect{|e| e}}
  850.   end
  851.   
  852.   #--
  853.   # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  854.   #++
  855.   
  856.   #
  857.   # Overrides Object#to_s
  858.   #
  859.   def to_s
  860.     "Matrix[" + @rows.collect{
  861.       |row|
  862.       "[" + row.collect{|e| e.to_s}.join(", ") + "]"
  863.     }.join(", ")+"]"
  864.   end
  865.   
  866.   #
  867.   # Overrides Object#inspect
  868.   #
  869.   def inspect
  870.     "Matrix"+@rows.inspect
  871.   end
  872.   
  873.   # Private CLASS
  874.   
  875.   class Scalar < Numeric # :nodoc:
  876.     include ExceptionForMatrix
  877.     
  878.     def initialize(value)
  879.       @value = value
  880.     end
  881.     
  882.     # ARITHMETIC
  883.     def +(other)
  884.       case other
  885.       when Numeric
  886.         Scalar.new(@value + other)
  887.       when Vector, Matrix
  888.         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
  889.       when Scalar
  890.         Scalar.new(@value + other.value)
  891.       else
  892.         x, y = other.coerce(self)
  893.         x + y
  894.       end
  895.     end
  896.     
  897.     def -(other)
  898.       case other
  899.       when Numeric
  900.         Scalar.new(@value - other)
  901.       when Vector, Matrix
  902.         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
  903.       when Scalar
  904.         Scalar.new(@value - other.value)
  905.       else
  906.         x, y = other.coerce(self)
  907.         x - y
  908.       end
  909.     end
  910.     
  911.     def *(other)
  912.       case other
  913.       when Numeric
  914.         Scalar.new(@value * other)
  915.       when Vector, Matrix
  916.         other.collect{|e| @value * e}
  917.       else
  918.         x, y = other.coerce(self)
  919.         x * y
  920.       end
  921.     end
  922.     
  923.     def / (other)
  924.       case other
  925.       when Numeric
  926.         Scalar.new(@value / other)
  927.       when Vector
  928.         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
  929.       when Matrix
  930.         self * _M.inverse
  931.       else
  932.         x, y = other.coerce(self)
  933.         x / y
  934.       end
  935.     end
  936.     
  937.     def ** (other)
  938.       case other
  939.       when Numeric
  940.         Scalar.new(@value ** other)
  941.       when Vector
  942.         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
  943.       when Matrix
  944.         other.powered_by(self)
  945.       else
  946.         x, y = other.coerce(self)
  947.         x ** y
  948.       end
  949.     end
  950.   end
  951. end
  952.  
  953.  
  954. #
  955. # The +Vector+ class represents a mathematical vector, which is useful in its own right, and
  956. # also constitutes a row or column of a Matrix.
  957. #
  958. # == Method Catalogue
  959. #
  960. # To create a Vector:
  961. # * <tt>  Vector.[](*array)                   </tt>
  962. # * <tt>  Vector.elements(array, copy = true) </tt>
  963. #
  964. # To access elements:
  965. # * <tt>  [](i)                               </tt>
  966. #
  967. # To enumerate the elements:
  968. # * <tt> #each2(v)                            </tt>
  969. # * <tt> #collect2(v)                         </tt>
  970. #
  971. # Vector arithmetic:
  972. # * <tt>  *(x) "is matrix or number"          </tt>
  973. # * <tt>  +(v)                                </tt>
  974. # * <tt>  -(v)                                </tt>
  975. #
  976. # Vector functions:
  977. # * <tt> #inner_product(v)                    </tt>
  978. # * <tt> #collect                             </tt>
  979. # * <tt> #map                                 </tt>
  980. # * <tt> #map2(v)                             </tt>
  981. # * <tt> #r                                   </tt>
  982. # * <tt> #size                                </tt>
  983. #
  984. # Conversion to other data types:
  985. # * <tt> #covector                            </tt>
  986. # * <tt> #to_a                                </tt>
  987. # * <tt> #coerce(other)                       </tt>
  988. #
  989. # String representations:
  990. # * <tt> #to_s                                </tt>
  991. # * <tt> #inspect                             </tt>
  992. #
  993. class Vector
  994.   include ExceptionForMatrix
  995.   
  996.   #INSTANCE CREATION
  997.   
  998.   private_class_method :new
  999.  
  1000.   #
  1001.   # Creates a Vector from a list of elements.
  1002.   #   Vector[7, 4, ...]
  1003.   #
  1004.   def Vector.[](*array)
  1005.     new(:init_elements, array, copy = false)
  1006.   end
  1007.   
  1008.   #
  1009.   # Creates a vector from an Array.  The optional second argument specifies
  1010.   # whether the array itself or a copy is used internally.
  1011.   #
  1012.   def Vector.elements(array, copy = true)
  1013.     new(:init_elements, array, copy)
  1014.   end
  1015.   
  1016.   #
  1017.   # For internal use.
  1018.   #
  1019.   def initialize(method, array, copy)
  1020.     self.send(method, array, copy)
  1021.   end
  1022.   
  1023.   #
  1024.   # For internal use.
  1025.   #
  1026.   def init_elements(array, copy)
  1027.     if copy
  1028.       @elements = array.dup
  1029.     else
  1030.       @elements = array
  1031.     end
  1032.   end
  1033.   
  1034.   # ACCESSING
  1035.          
  1036.   #
  1037.   # Returns element number +i+ (starting at zero) of the vector.
  1038.   #
  1039.   def [](i)
  1040.     @elements[i]
  1041.   end
  1042.   
  1043.   #
  1044.   # Returns the number of elements in the vector.
  1045.   #
  1046.   def size
  1047.     @elements.size
  1048.   end
  1049.   
  1050.   #--
  1051.   # ENUMERATIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1052.   #++
  1053.  
  1054.   #
  1055.   # Iterate over the elements of this vector and +v+ in conjunction.
  1056.   #
  1057.   def each2(v) # :yield: e1, e2
  1058.     Vector.Raise ErrDimensionMismatch if size != v.size
  1059.     0.upto(size - 1) do
  1060.       |i|
  1061.       yield @elements[i], v[i]
  1062.     end
  1063.   end
  1064.   
  1065.   #
  1066.   # Collects (as in Enumerable#collect) over the elements of this vector and +v+
  1067.   # in conjunction.
  1068.   #
  1069.   def collect2(v) # :yield: e1, e2
  1070.     Vector.Raise ErrDimensionMismatch if size != v.size
  1071.     (0 .. size - 1).collect do
  1072.       |i|
  1073.       yield @elements[i], v[i]
  1074.     end
  1075.   end
  1076.  
  1077.   #--
  1078.   # COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1079.   #++
  1080.  
  1081.   #
  1082.   # Returns +true+ iff the two vectors have the same elements in the same order.
  1083.   #
  1084.   def ==(other)
  1085.     return false unless Vector === other
  1086.     
  1087.     other.compare_by(@elements)
  1088.   end
  1089.   alias eqn? ==
  1090.   
  1091.   #
  1092.   # For internal use.
  1093.   #
  1094.   def compare_by(elements)
  1095.     @elements == elements
  1096.   end
  1097.   
  1098.   #
  1099.   # Return a copy of the vector.
  1100.   #
  1101.   def clone
  1102.     Vector.elements(@elements)
  1103.   end
  1104.   
  1105.   #
  1106.   # Return a hash-code for the vector.
  1107.   #
  1108.   def hash
  1109.     @elements.hash
  1110.   end
  1111.   
  1112.   #--
  1113.   # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1114.   #++
  1115.   
  1116.   #
  1117.   # Multiplies the vector by +x+, where +x+ is a number or another vector.
  1118.   #
  1119.   def *(x)
  1120.     case x
  1121.     when Numeric
  1122.       els = @elements.collect{|e| e * x}
  1123.       Vector.elements(els, false)
  1124.     when Matrix
  1125.       Matrix.column_vector(self) * x
  1126.     else
  1127.       s, x = x.coerce(self)
  1128.       s * x
  1129.     end
  1130.   end
  1131.  
  1132.   #
  1133.   # Vector addition.
  1134.   #
  1135.   def +(v)
  1136.     case v
  1137.     when Vector
  1138.       Vector.Raise ErrDimensionMismatch if size != v.size
  1139.       els = collect2(v) {
  1140.         |v1, v2|
  1141.         v1 + v2
  1142.       }
  1143.       Vector.elements(els, false)
  1144.     when Matrix
  1145.       Matrix.column_vector(self) + v
  1146.     else
  1147.       s, x = v.coerce(self)
  1148.       s + x
  1149.     end
  1150.   end
  1151.  
  1152.   #
  1153.   # Vector subtraction.
  1154.   #
  1155.   def -(v)
  1156.     case v
  1157.     when Vector
  1158.       Vector.Raise ErrDimensionMismatch if size != v.size
  1159.       els = collect2(v) {
  1160.         |v1, v2|
  1161.         v1 - v2
  1162.       }
  1163.       Vector.elements(els, false)
  1164.     when Matrix
  1165.       Matrix.column_vector(self) - v
  1166.     else
  1167.       s, x = v.coerce(self)
  1168.       s - x
  1169.     end
  1170.   end
  1171.   
  1172.   #--
  1173.   # VECTOR FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1174.   #++
  1175.   
  1176.   #
  1177.   # Returns the inner product of this vector with the other.
  1178.   #   Vector[4,7].inner_product Vector[10,1]  => 47
  1179.   #
  1180.   def inner_product(v)
  1181.     Vector.Raise ErrDimensionMismatch if size != v.size
  1182.     
  1183.     p = 0
  1184.     each2(v) {
  1185.       |v1, v2|
  1186.       p += v1 * v2
  1187.     }
  1188.     p
  1189.   end
  1190.   
  1191.   #
  1192.   # Like Array#collect.
  1193.   #
  1194.   def collect # :yield: e
  1195.     els = @elements.collect {
  1196.       |v|
  1197.       yield v
  1198.     }
  1199.     Vector.elements(els, false)
  1200.   end
  1201.   alias map collect
  1202.   
  1203.   #
  1204.   # Like Vector#collect2, but returns a Vector instead of an Array.
  1205.   #
  1206.   def map2(v) # :yield: e1, e2
  1207.     els = collect2(v) {
  1208.       |v1, v2|
  1209.       yield v1, v2
  1210.     }
  1211.     Vector.elements(els, false)
  1212.   end
  1213.   
  1214.   #
  1215.   # Returns the modulus (Pythagorean distance) of the vector.
  1216.   #   Vector[5,8,2].r => 9.643650761
  1217.   #
  1218.   def r
  1219.     v = 0
  1220.     for e in @elements
  1221.       v += e*e
  1222.     end
  1223.     return Math.sqrt(v)
  1224.   end
  1225.   
  1226.   #--
  1227.   # CONVERTING
  1228.   #++
  1229.  
  1230.   #
  1231.   # Creates a single-row matrix from this vector.
  1232.   #
  1233.   def covector
  1234.     Matrix.row_vector(self)
  1235.   end
  1236.   
  1237.   #
  1238.   # Returns the elements of the vector in an array.
  1239.   #
  1240.   def to_a
  1241.     @elements.dup
  1242.   end
  1243.   
  1244.   #
  1245.   # FIXME: describe Vector#coerce.
  1246.   #
  1247.   def coerce(other)
  1248.     case other
  1249.     when Numeric
  1250.       return Scalar.new(other), self
  1251.     else
  1252.       raise TypeError, "#{self.class} can't be coerced into #{other.class}"
  1253.     end
  1254.   end
  1255.   
  1256.   #--
  1257.   # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1258.   #++
  1259.   
  1260.   #
  1261.   # Overrides Object#to_s
  1262.   #
  1263.   def to_s
  1264.     "Vector[" + @elements.join(", ") + "]"
  1265.   end
  1266.   
  1267.   #
  1268.   # Overrides Object#inspect
  1269.   #
  1270.   def inspect
  1271.     str = "Vector"+@elements.inspect
  1272.   end
  1273. end
  1274.  
  1275.  
  1276. # Documentation comments:
  1277. #  - Matrix#coerce and Vector#coerce need to be documented
  1278.